﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EndlessGalaxy
{
    public class Cargo
    {
        public static List<string> gases;
        public static List<string> liquids;
        public static List<string> solids;
        public enum Phases { solid, liquid, gas, plasma, other };
        public Phases phase;
        public string name;
        public double amount;//tonnes (1000kg)
        public double density;

        public Cargo()
        {
            name = "NULLREF";
            phase = Phases.other;
            amount = 0;
            density = 0;
        }

        public Cargo(Cargo source, double amt)
        {
            phase = source.phase;
            name = source.name;
            amount = amt;
            density = source.density;
        }

        public Cargo(string Name, double amt, Phases Phase)
        {
            if (Globals.materials.Keys.Contains<string>(Name))
            {
                name = Globals.materials[Name].name;
                amount = amt;
                phase = Phase;
                switch (phase)
                {
                    case Phases.plasma:
                    case Phases.gas:
                        density = Globals.materials[Name].densityG;
                        break;
                    case Phases.liquid:
                    case Phases.other:
                        density = Globals.materials[Name].densityL;
                        break;
                    case Phases.solid:
                    default:
                        density = Globals.materials[Name].densityS;
                        break;
                }
            }
            else
            {
                name = "NullRef";
                amount = 0.0;
                phase = Phases.other;
                density = 0.0;
            }
        }

        public static List<Cargo> StellarMass(double size)
        {
            List<Cargo> stuff = new List<Cargo>();
            List<string> names = new List<string>();
            foreach (SuperCargo items in Globals.materials.Values)
            {
                if (items.attributes.Contains("STELLAR_COMMON"))
                {
                    names.Add(items.name);
                    names.Add(items.name);
                    names.Add(items.name);
                }
                if (items.attributes.Contains("STELLAR_UNCOMMON"))
                {
                    names.Add(items.name);
                    names.Add(items.name);
                }
                if (items.attributes.Contains("STELLAR_RARE"))
                {
                    names.Add(items.name);
                }
            }
            double multiplier = 4.0;
            for (int count = Globals.randint.Next(2, Math.Min(names.Count, 5)); count > 0; count--)
            {
                int i = Globals.randint.Next(names.Count);
                stuff.Add(new Cargo(names[i], Globals.randint.NextDouble() * Math.Pow(Math.Pow(Globals.solarmass,0.25), multiplier), Cargo.Phases.gas));
                multiplier *= Math.Sqrt(Globals.randint.NextDouble());
                string n = names[i];
                while (names.Contains(n))
                {
                    names.Remove(n);
                }
                if (names.Count < 1)
                {
                    break;
                }
            }
            #region traces
            names = new List<string>();
            foreach (SuperCargo items in Globals.materials.Values)
            {
                if (items.attributes.Contains("STELLAR_TRACE"))
                {
                    names.Add(items.name);
                }
            }
            double gravity = 0.0;
            foreach (Cargo item in stuff)
            {
                gravity += item.amount;
            }
            for (int count = Globals.randint.Next(0, Math.Min(names.Count + 1, 3)); count > 0; count--)
            {
                int i = Globals.randint.Next(names.Count);
                stuff.Add(new Cargo(names[i], Globals.randint.NextDouble() * Math.Pow(gravity , (1.0/3.0)), Cargo.Phases.solid));
                string n = names[i];
                while (names.Contains(n))
                {
                    names.Remove(n);
                }
                if (names.Count < 1)
                {
                    break;
                }
            }
            #endregion
            return stuff;
        }

        public override string ToString()
        {
            return name + ", " + Convert.ToString(amount) + " tonnes";
        }

        public static double FreeSpace(double space, List<Cargo> contents)
        {
            double free = space;
            foreach (Cargo item in contents)
            {
                free -= item.amount;
            }
            return free;
        }

        public static bool HasContents(string name, List<Cargo> from)
        {
            foreach (Cargo thing in from)
            {
                if (thing.name == name)
                {
                    if (thing.amount <= 0)
                    {
                        return false;
                    }
                    return true;
                }
            }
            return false;
        }
        public static bool HasContents(string name, List<Cargo> from, double amt)
        {
            foreach (Cargo thing in from)
            {
                if (thing.name == name)
                {
                    if (thing.amount < amt)
                    {
                        return false;
                    }
                    return true;
                }
            }
            return false;
        }

        public static Cargo TakeCargo(string name, double amount, List<Cargo> from)
        {
            double finalamount = amount;
            Cargo final = new Cargo();
            for (int i = from.Count - 1; i >= 0; i--)
            {
                if (from[i].name == name)
                {
                    finalamount = Math.Min(amount, from[i].amount);
                    final = new Cargo(from[i], finalamount);
                    from[i].amount -= finalamount;
                    if (from[i].amount <= 0)
                    {
                        from.RemoveAt(i);
                    }
                    break;
                }
            }
            return final;
        }

        public static void GiveCargo(Cargo thing, List<Cargo> to)
        {
            foreach (Cargo stuff in to)
            {
                if (stuff.name == thing.name)
                {
                    stuff.amount += thing.amount;
                    return;
                }
            }
            to.Add(thing);
        }
        public static void GiveCargo(string Name, double amount, List<Cargo> to)
        {
            foreach (Cargo stuff in to)
            {
                if (stuff.name == Name)
                {
                    stuff.amount += amount;
                    return;
                }
            }
            to.Add(new Cargo(Name, amount, Globals.materials[Name].phase));
        }

        public static double Sum(List<Cargo> stuff)
        {
            double total = 0;
            foreach (Cargo item in stuff)
            {
                total += item.amount;
            }
            return total;
        }

        public static bool hasAttribute(List<Cargo> l, string att)
        {
            foreach (Cargo item in l)
            {
                if (Globals.materials[item.name].attributes.Contains(att))
                {
                    return true;
                }
            }
            return false;
        }
    }

    public class SuperCargo
    {
        public string name;
        public bool elemental;
        public int elementnum;
        public int stableneutrons;
        public string formula; //elemental symbol or chemical formula
        public double densityG;
        public double densityL;
        public double densityS;
        public double meltPoint;
        public double boilPoint;
        public Cargo.Phases phase;
        public List<string> attributes;
        public SuperCargo()
        {
            attributes = new List<string>();
            elemental = false;
        }

        public Dictionary<string, double> contents()
        {
            Dictionary<string, double> stuff = new Dictionary<string, double>();
            double total = 0;
            if (elemental)
            {
                stuff.Add(name, 1.0);
                total = 1.0;
            }
            else
            {
                string num = "";
                string symbol = "";
                string name = "";
                double n = 1.0;
                for (int i = 0; i < formula.Length; i++)
                {
                    switch (formula[i])
                    {
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                        case '0':
                            num += formula[i];
                            break;
                        case 'A':
                        case 'B':
                        case 'C':
                        case 'D':
                        case 'E':
                        case 'F':
                        case 'G':
                        case 'H':
                        case 'I':
                        case 'J':
                        case 'K':
                        case 'L':
                        case 'M':
                        case 'N':
                        case 'O':
                        case 'P':
                        case 'Q':
                        case 'R':
                        case 'S':
                        case 'T':
                        case 'U':
                        case 'V':
                        case 'W':
                        case 'X':
                        case 'Y':
                        case 'Z':
                            if (symbol != "")
                            {
                                name = parseSymbol(symbol);
                                if (!double.TryParse(num, out n))
                                {
                                    n = 1.0;
                                }
                                total += n;
                                stuff.Add(name, n);
                                num = "";
                            }
                            symbol = Convert.ToString(formula[i]);
                            break;
                        case 'a':
                        case 'b':
                        case 'c':
                        case 'd':
                        case 'e':
                        case 'f':
                        case 'g':
                        case 'h':
                        case 'i':
                        case 'j':
                        case 'k':
                        case 'l':
                        case 'm':
                        case 'n':
                        case 'o':
                        case 'p':
                        case 'q':
                        case 'r':
                        case 's':
                        case 't':
                        case 'u':
                        case 'v':
                        case 'w':
                        case 'x':
                        case 'y':
                        case 'z':
                            symbol += formula[i];
                            break;
                    }
                }
                name = parseSymbol(symbol);
                n = 1.0;
                if (!double.TryParse(num, out n))
                {
                    n = 1.0;
                }
                total += n;
                stuff.Add(name, n);
            }
            List<string> names = new List<string>();
            foreach (string name in stuff.Keys)
            {
                names.Add(name);
            }
            foreach (string name in names)
            {
                stuff[name] /= total;
            }
            return stuff;
        }

        public static string parseSymbol(string symbol)
        {
            foreach (SuperCargo stuff in Globals.materials.Values)
            {
                if (stuff.formula == symbol)
                {
                    return stuff.name;
                }
            }
            return "";
        }

        public static Cargo GiveWithAttribute(string att, double amount)
        {
            List<SuperCargo> items = new List<SuperCargo>();
            foreach (SuperCargo stuff in Globals.materials.Values)
            {
                if (stuff.attributes.Contains(att))
                {
                    items.Add(stuff);
                }
            }
            if (items.Count <= 0)
            {
                return new Cargo("NullRef", 0.0, Cargo.Phases.other);
            }
            return new Cargo(items[Globals.randint.Next(items.Count)].name, amount, Cargo.Phases.solid);
        }
    }
}